/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hhf.flex.ascreator.patterns;

import hhf.flex.annotations.services.CanceledService;
import hhf.flex.ascreator.ASClassCreator;
import hhf.flex.ascreator.exceptions.IllegalParameterException;
import hhf.flex.ascreator.exceptions.MissingAnnotationException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 *
 * @author utilisateur
 */
public class ASCancelFunctionPattern {

    /**
     * Permet d'écrire une fonction de type "cancelFuncrion" qui annule
     * des données en cache d'autres services que le service courant.
     * @param out
     * @param canceledService
     * @param annotedNames
     * @param argsTyped
     * @return
     * @throws IOException
     * @throws IllegalParameterException
     * @throws MissingAnnotationException 
     */
    public static String writeOneCancelFunction(OutputStreamWriter out, CanceledService canceledService, Map<String, String> annotedNames, Map<String, Class> annotedClass, String argsTyped, Method method) throws IOException, IllegalParameterException, MissingAnnotationException {


        //sera le nom de la fonction générée
        String functionName = canceledService.methodClass().toString();

        //pour éliminer le "class " devant le nom du package
        functionName = functionName.split(" ")[1];

        functionName += canceledService.method();
        String[] parameters = canceledService.parameters();
        String allParameters = "";
        String loops = "";
        int braces = 0;
        int indentations = 4;
        boolean flag = false;
        Class<?> lastClass = null;
        Class subClass = null;
        for (String parameter : parameters) {
            if (flag) {
                allParameters += ", ";
            }
            String[] hashString = parameter.split("\\.");
            String lastVariable = "";
            for (int i = 0; i < hashString.length; i++) {
                String current = hashString[i];
                if (i == 0) {
                    String trueName = annotedNames.get(current);
                    lastClass = annotedClass.get(current);
                    if (trueName != null) {


                        if ((lastClass.equals(List.class) || (lastClass.equals(Collection.class)) || (lastClass.isArray()))) {
                            loops += getTabs(indentations);
                            loops += "\tfor each(var " + trueName + "_" + ":Object in " + trueName + ") {\n";
                            braces++;
                            indentations++;
                            allParameters += trueName + "_";
                            lastVariable = trueName + "_";

                            try {
                                String encaps = ASClassCreator.getMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes()).toGenericString();
                                int len = encaps.split(" ").length;
                                encaps = encaps.split(" ")[len - 1].split("<")[1].split(">")[0];
                                lastClass = Class.forName(encaps);
                            } catch (ClassNotFoundException ex) {
                                throw new IllegalParameterException(ex.getMessage());
                            } catch (NoSuchMethodException ex) {
                                throw new IllegalParameterException(ex.getMessage());
                            }

                        } else {
                            allParameters += trueName;
                            lastVariable = trueName;
                        }
                        functionName += "_" + trueName;
                    } else {
                        throw new MissingAnnotationException("L'argument " + current + " ne correspond à aucun @ArgumentName.");
                    }
                } else {
                    Class currentClass = null;
                    String genericString = null;
                    String subClassString = null;
                    boolean inArray = false;

                    try {
                        if (ASClassCreator.getField(lastClass, current).toGenericString().split(" ")[1].split("<").length != 2) {
                            genericString = ASClassCreator.getField(lastClass, current).toGenericString().split(" ")[1].split("<")[0];
                            currentClass = Class.forName(genericString);
                        } else {
                            subClassString = ASClassCreator.getField(lastClass, current).toGenericString().split(" ")[1].split("<")[1].split(">")[0];
                            currentClass = Class.forName(subClassString);
                            inArray = true;
                        }

                    } catch (ClassNotFoundException ex) {
                        throw new IllegalParameterException("\n" + genericString + " : ClassNotFound");
                    } catch (NoSuchFieldException ex) {
                        throw new IllegalParameterException("NoSuchFieldException!!!!");
                    } catch (NullPointerException ex) {
                        throw new IllegalParameterException("NullPointerException ");
                    }

                    if (inArray) {
                        String variable = current + "_";
                        variable = variable.replace('(', '_');
                        variable = variable.replace(')', '_');
                        loops += getTabs(indentations);
                        allParameters += "." + variable;
                        loops += "for each(var " + variable + ":Object in " + lastVariable + "." + current + ") {\n";
                        lastVariable = variable;
                        braces++;
                        indentations++;
                        functionName += "_" + variable;
                        try {
                            lastClass = Class.forName(subClassString);
                        } catch (ClassNotFoundException ex) {
                            throw new IllegalParameterException("\n" + subClassString + " : ClassNotFound");
                        }
                    } else {
                        String variable = current + "_";
                        variable = variable.replace('(', '_');
                        variable = variable.replace(')', '_');
                        functionName += "_" + variable;
                        allParameters += "." + current;
                        lastClass = currentClass;
                    }
                }
            }
            flag = true;
        }
        functionName = functionName.replace(" ", "_");
        functionName = functionName.replace(".", "_");
        //début de l'écriture de la fonction				
        out.write("\t\tprivate function cancel_" + functionName + "(" + argsTyped + "):void {\n");

        String cacheService = canceledService.methodClass().getPackage().getName();
        String classNameBis = canceledService.methodClass().getSimpleName();
        cacheService += "." + classNameBis.substring(0, 1).toLowerCase() + classNameBis.substring(1);

        cacheService += "." + canceledService.method();
        String call = cacheService + ".getCacheServiceId(" + allParameters + ")";
        cacheService += "CacheService";
        out.write(loops);
        out.write(getTabs(indentations));
        out.write("try {\n");
        out.write(getTabs(indentations));
        out.write("var srvid:String = " + call + ";\n");
        out.write(getTabs(indentations));
        out.write("var o:" + cacheService + " = em.find(" + cacheService + ", srvid );\n");
        out.write(getTabs(indentations));
        out.write("em.remove(o);\n");
        out.write(getTabs(indentations - 1));
        out.write("}\tcatch (e:EntityNotFoundException){ }\n");
        out.write(getTabs(indentations - 1));
        out.write("\tcatch (e:NoResultException){ }\n");
        for (int j = 0; j < braces; j++) {
            indentations--;
            out.write(getTabs(indentations));
            out.write("}\n");
        }
        out.write("\t\t\t\n");
        out.write("\t\t}\n");
        return functionName;
    }

    private static String getTabs(int tabs) {
        String result = "";
        for (int i = 0; i < tabs; i++) {
            result += "\t";
        }
        return result;
    }
}
